
// -----------------------------------------------------------------------------

#include "stdafx.h"
#include "Win32.Xml.XmlLiteReader.h"

namespace XML = Kif::Win32::Xml;

namespace Kif
{
namespace Win32
{
namespace Xml
{

/// <summary>Initialize the XML Reader to read the given XML document</summary>
/// <param name="filePath">the file path is returned</param>
/// <returns>A pointer to the XML Reader is returned if all is ok, else
/// NULL is returned.</returns>
XmlLiteReader *XmlLiteReader::CreateXmlReader(TCHAR *filePath)
{
   if (strTextReader.OpenTextReader(filePath) == NULL)
      return NULL;

   if (FAILED(lastHResult = ::CreateXmlReader(__uuidof(IXmlReader), 
      (void**)&pReader, NULL)))
      return NULL;

   if (FAILED(lastHResult = pReader->SetInput(strTextReader.GetFileStream())))
      return NULL;

   return NULL;
}  // end of XmlLiteReader::createXmlReader

/// <summary>Read attribute and value.  Caller should not release the returned
/// pointer since it is allocated in this instance and will be release
/// later.</summary>
/// <param name="attributeName">name of attribute of current element to be
/// read and to fetch value of...</param>
/// <param name="attribute">attribute info as defined in XmlNodeAttribute
/// </param>
/// <returns>A pointer to the last read attribute is returned.</returns>
XmlNodeAttribute *XmlLiteReader::ReadAttributeValue(
   TCHAR *attributeName, XmlNodeAttribute &attribute)
{
   if (FAILED(attribute.lastHResult =
      pReader->MoveToAttributeByName(attributeName, NULL)))                    
   {
      attribute.ErrorMessage.Copy(L"Error reading attribute name");
      attribute.Value.Dispose();
      attribute.Succeeded = false;
      return(NULL);
   }

   if (attribute.lastHResult == S_OK)
   {
      const wchar_t* pValue;
      if (FAILED(attribute.lastHResult = pReader->GetValue(&pValue, NULL)))
      {
         attribute.ErrorMessage.Copy(L"Error reading attribute value");
         attribute.Value.Dispose();
         attribute.Succeeded = false;
      }
      else
      {
         attribute.Value.Copy((wchar_t*)pValue);
         attribute.Succeeded = true;
      }
   }
   else
   {
      attribute.Value.Dispose();
      attribute.Succeeded = false;
   }

   return(attribute.Succeeded ? &attribute : NULL);
}  // end of XmlLiteReader::ReadAttributeValue

/// <summary>Read Element node.</summary>
/// <param name="node">node reference info read</param>
/// <returns>true is returned if reading should move to next element or
/// an error was found to allow caller to handle it</returns>
bool XmlLiteReader::ReadElement(XmlNodeReference &node)
{
   const wchar_t *pName;

   // read the full Qualified-Name...
   if (ReadQualifiedName)
   {
      if (FAILED(lastHResult = pReader->GetQualifiedName(&pName, NULL)))                      
      {
         node.pErrorMessage = L"Error reading element qualified-name";
         return true;
      }

      if (lastHResult == S_OK)
      {
         node.pName = pName;
         node.Succeeded = true;
      }
   }

   // read prefix (namespace) and tag (separately)
   else
   {
      const wchar_t *pPrefix;
      UINT cwchPrefix;

      if (FAILED(lastHResult = pReader->GetPrefix(&pPrefix, &cwchPrefix)))                      
      {
         node.pErrorMessage = L"Error reading element prefix-name";
         return true;
      }

      if (lastHResult == S_OK)
         node.pPrefix = pPrefix;

      if (FAILED(lastHResult = pReader->GetLocalName(&pName, NULL)))                      
      {
         node.pErrorMessage = L"Error reading element local-name";
         return true;
      }

      if (lastHResult == S_OK)
      {
         node.pName = pName;
         node.Succeeded = true;
      }
   }

   return true;
}  // end of XmlLiteReader::ReadElement

/// <summary>Read ProcessingInstruction node of the form '?pi test?'.</summary>
/// <param name="node">node reference info read</param>
/// <returns>true is returned if reading should move to next element or
/// an error was found to allow caller to handle it</returns>
bool XmlLiteReader::ReadProcessingInstruction(XmlNodeReference &node)
{
   const wchar_t *pName,*pValue;
   if (FAILED(lastHResult = pReader->GetLocalName(&pName, NULL)))
   {
      node.pErrorMessage = L"Error getting ProcessingInstruction name";
      return true;
   }

   if (lastHResult == S_OK)
      node.pName = pName;

   if (FAILED(lastHResult = pReader->GetValue(&pValue, NULL)))
   {
      node.pErrorMessage = L"Error getting ProcessingInstruction value";
      return true;
   }

   if (lastHResult == S_OK)
   {
      node.pValue = pValue;
      node.Succeeded = true;
   }

   return true;
}  // end of XmlLiteReader::ReadProcessingInstruction

/// <summary>To read a document the user will call this Read method until all
/// nodes have been read.</summary>
/// <param name="node">node reference info read</param>
/// <returns>the reference node is returned if the node had been read else
// the node info contains the information about the issue found</returns>
XmlNodeReference *XmlLiteReader::Read(XmlNodeReference &node)
{
   bool done = false;

   node.Succeeded = false;
   node.ClearFields();
   while (!done)
   {
      if (S_OK != (lastHResult = pReader->Read(&node.LastReadNodeType)))
         return(false);

      switch (node.LastReadNodeType)
      {
         case XmlNodeType_Element:
            done = ReadElement(node);
            break;

         case XmlNodeType_EndElement:
            done = ReadElement(node);
            break;

         case XmlNodeType_Text:
            done = ReadValue(node);
            break;

         case XmlNodeType_CDATA:
            done = ReadValue(node);
            break;

         case XmlNodeType_XmlDeclaration:
            break;

         case XmlNodeType_ProcessingInstruction:
            if (ReadProcessingInstructions)
            {
               done = ReadProcessingInstruction(node);
            }
            break;

         case XmlNodeType_Comment:
            if (ReadComments)
            {
               done = ReadValue(node);
            }
            break;

         case XmlNodeType_DocumentType:
            break;

         case XmlNodeType_Whitespace:
            break;

         default:
            node.pErrorMessage =
               L"Error invalid/unknown not supported node type";
            done = true;
            node.Succeeded = false;
            break;
      }
   }
   return(&node);
}  // end of XmlLiteReader::Read

}  // end of Kif::Win32::Xml namespace
}  // end of Kif::Win32 namespace
}  // end of Kif namespace

// -----------------------------------------------------------------------------

